﻿using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using IOP.Orleans.MessageHub;
using Microsoft.Extensions.Logging;
using Orleans;
using Microsoft.Extensions.Options;

namespace IOP.Orleans.Service.MessageHub
{
    /// <summary>
    /// 消息服务
    /// </summary>
    public class MessageHubService : IMessageHubService
    {
        /// <summary>
        /// 客户端
        /// </summary>
        public IClusterClient Client { get; private set; }
        /// <summary>
        /// 日志工厂
        /// </summary>
        private readonly ILoggerFactory _Factory;
        /// <summary>
        /// 监听者字典
        /// </summary>
        private readonly ConcurrentDictionary<string, IMessageDispatcher> _ObserverDictionary = new ConcurrentDictionary<string, IMessageDispatcher>();
        /// <summary>
        /// 配置
        /// </summary>
        private readonly MessageHubServiceOption _Option;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public MessageHubService(IClusterClient client, ILoggerFactory loggerFactory, IOptions<MessageHubServiceOption> option)
        {
            _Factory = loggerFactory;
            Client = client;
            _Option = option.Value;
        }

        /// <summary>
        /// 注册监听者
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <param name="customMessageHandle"></param>
        public async Task<IMessageDispatcher> RegistObserver<TMessage>(Func<TMessage, Task> customMessageHandle, string prefix)
            where TMessage : class
        {
            if (customMessageHandle == null) throw new ArgumentNullException(nameof(customMessageHandle));
            IMessageDispatcher<TMessage> msgOb;
            if (_ObserverDictionary.TryGetValue(prefix, out IMessageDispatcher ob))
            {
                msgOb = ob as IMessageDispatcher<TMessage>;
                if (msgOb == null) throw new InvalidCastException($"{nameof(IMessageDispatcher)} convert to {nameof(IMessageDispatcher<TMessage>)} Failed");
                await msgOb.RegistMessageHandle(customMessageHandle);
            }
            else
            {
                msgOb = await RegistDefaultObserver<TMessage>(Client, prefix);
                await msgOb.RegistMessageHandle(customMessageHandle);
            }
            return msgOb;
        }
        /// <summary>
        /// 发布一条消息
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <param name="message"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public async Task PublishMessage<TMessage>(TMessage message, string prefix) where TMessage : class
        {
            var ob = _ObserverDictionary.TryGetValue(prefix, out IMessageDispatcher observer);
            if (!ob) await RegistDefaultObserver<TMessage>(Client, prefix);
            else
            {
                IMessageDispatcher<TMessage> old = observer as IMessageDispatcher<TMessage>;
                if (old == null) throw new InvalidCastException($"{nameof(IMessageDispatcher)} convert to {nameof(IMessageDispatcher<TMessage>)} Failed");
                await old.SendMessage(message);
            }
        }

        /// <summary>
        /// 注册一个监听者开始监听的事件
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="prefix"></param>
        public IMessageDispatcher RegistObserverBeginListenedEvent(Func<IMessageDispatcher, Task> handle, string prefix)
        {
            if (handle == null) throw new ArgumentNullException(nameof(handle));
            if (_ObserverDictionary.TryGetValue(prefix, out IMessageDispatcher ob))
            {
                ob.OnObserverAbortListened -= null;
                ob.OnObserverBeginListened += handle;
                return ob;
            }
            else throw new NullReferenceException($"The MessageDispatcher with name {prefix} has not regist, please use method RegistObserver to create");
        }
        /// <summary>
        /// 注册一个监听者停止监听的事件
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public IMessageDispatcher RegistObserverAbortListenedEvent(Func<IMessageDispatcher, Task> handle, string prefix)
        {
            if (handle == null) throw new ArgumentNullException(nameof(handle));
            if (_ObserverDictionary.TryGetValue(prefix, out IMessageDispatcher ob))
            {
                ob.OnObserverAbortListened -= null;
                ob.OnObserverAbortListened += handle;
                return ob;
            }
            else throw new NullReferenceException($"The MessageDispatcher with name {prefix} has not regist, please use method RegistObserver to create");
        }
        /// <summary>
        /// 注册一个健康检查函数
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public IMessageDispatcher RegistHealthCheckHandle(Func<byte[], Task> handle, string prefix)
        {
            if (handle == null) throw new ArgumentNullException(nameof(handle));
            if (_ObserverDictionary.TryGetValue(prefix, out IMessageDispatcher ob))
            {
                ob.RegistHealthCheckHandle(handle);
                return ob;
            }
            else throw new NullReferenceException($"The MessageDispatcher with name {prefix} has not regist, please use method RegistObserver to create");
        }
        /// <summary>
        /// 注册一个健康检查函数
        /// </summary>
        /// <param name="dispatcher"></param>
        /// <param name="handle"></param>
        /// <returns></returns>
        public IMessageDispatcher RegistHealthCheckHandle(IMessageDispatcher dispatcher, Func<byte[], Task> handle)
        {
            if (handle == null) throw new ArgumentNullException(nameof(handle));
            dispatcher.RegistHealthCheckHandle(handle);
            return dispatcher;
        }

        /// <summary>
        /// 注册一个监听者开始监听的事件
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="dispatcher"></param>
        public IMessageDispatcher RegistObserverBeginListenedEvent(IMessageDispatcher dispatcher, Func<IMessageDispatcher, Task> handle)
        {
            if (dispatcher == null) throw new ArgumentNullException(nameof(dispatcher));
            if(handle == null) throw new ArgumentNullException(nameof(dispatcher));
            dispatcher.OnObserverBeginListened -= null;
            dispatcher.OnObserverBeginListened += handle;
            return dispatcher;
        }
        /// <summary>
        /// 注册一个监听者停止监听的事件
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="dispatcher"></param>
        /// <returns></returns>
        public IMessageDispatcher RegistObserverAbortListenedEvent(IMessageDispatcher dispatcher, Func<IMessageDispatcher, Task> handle)
        {
            if (dispatcher == null) throw new ArgumentNullException(nameof(dispatcher));
            if (handle == null) throw new ArgumentNullException(nameof(dispatcher));
            dispatcher.OnObserverBeginListened -= null;
            dispatcher.OnObserverBeginListened += handle;
            return dispatcher;
        }

        /// <summary>
        /// 注册一个默认的监听者
        /// </summary>
        /// <returns></returns>
        private Task<MessageDispatcher<TMessage>> RegistDefaultObserver<TMessage>(IClusterClient client, string prefix)
            where TMessage : class
        {
            MessageDispatcher<TMessage> newOb = new MessageDispatcher<TMessage>(client, prefix, _Factory.CreateLogger<MessageDispatcher<TMessage>>());
            newOb.RegistMessageHandle((msg) => Task.CompletedTask);
            newOb.HealthCheck((int)_Option.HealthCheckPeriod.TotalMilliseconds);
            _ObserverDictionary.AddOrUpdate(prefix, newOb, (key, value) => value);
            return Task.FromResult(newOb);
        }
    }
}
